# Netty 快速掌握

## 1. 概述

本篇内容旨在帮你快速建立 Netty 知识体系，然后由抽象到具体快速掌握 Netty，看之前建议你先进行多线程和 IO 基础的学习，理清 IO 和线程之间的关联

## 2. 快速掌握 Netty 核心组件

- ServerBootstrap: 服务器的启动引导器，负责组装各核心组件。
- EventLoopGroup: 事件循环组，本质是一个线程池。
  - BossGroup: 负责接收客户端的连接请求。
  - WorkerGroup: 负责处理已建立连接的 I/O 读写业务。
- Channel: 网络连接的抽象。
  - NioServerSocketChannel: 服务器监听端口用的 Channel。
  - NioSocketChannel: 代表一个具体的客户端连接。
- ChannelInitializer: 通道初始化器，当新连接建立时，用于配置新 Channel 的 Pipeline。
- ChannelPipeline: 责任链，包含了一系列处理数据的 ChannelHandler。
  - ChannelHandler: 业务处理器，用于处理入站和出站事件/数据。

**核心关系与流程：**

ServerBootstrap 启动时配置 BossGroup（负责接收连接）和 WorkerGroup（负责处理 I/O 业务）。当新连接建立时，ChannelInitializer 会初始化该连接的 ChannelPipeline（业务处理链），这条管道定义了数据流入流出时需要经过的所有业务逻辑处理器。

**示例代码:**

```java
serverBootstrap.group(bossGroup, workerGroup)
               .channel(NioServerSocketChannel.class) // Channel
               .childHandler(new ChannelInitializer<SocketChannel>() { // ChannelInitializer Worker处理具体连接
                   @Override
                   public void initChannel(SocketChannel ch) {
                       // 这里是为Worker管理的连接配置Pipeline
                      ChannelPipeline p = ch.pipeline();
                      // 1. 先添加编解码器（也是Handler）
                      p.addLast(new StringDecoder());
                      p.addLast(new StringEncoder());
                      // 2. 再添加业务逻辑Handler
                      p.addLast(new MyBusinessLogicHandler());
                   }
               });
```

**一个完整的工作流程描述**

ServerBootstrap 启动，BossGroup 中的 EventLoop 通过 NioServerSocketChannel 监听端口。当有新连接时，BossGroup 接受连接并创建一个新的 SocketChannel，将其注册到 WorkerGroup 的一个 EventLoop 上。随后，ChannelInitializer 被调用，为该 SocketChannel 初始化 ChannelPipeline。该连接的所有 I/O 事件都由绑定的 EventLoop 驱动，在 ChannelPipeline 中流动，经过各个 ChannelHandler 处理。

## 3. 关键特性总结

**异步事件驱动**

所有 I/O 操作都是异步的，调用立即返回 ChannelFuture，通过添加监听器获取操作结果。这种模型使得线程无需阻塞等待 I/O 完成，可以处理更多连接。

```java
ChannelFuture future = channel.writeAndFlush(data);
future.addListener((ChannelFuture f) -> {
    if (f.isSuccess()) {
        System.out.println("写入成功");
    } else {
        System.out.println("写入失败: " + f.cause());
    }
});
```
